/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * DemoApplication.java
 *
 * Created on 2011/8/10, 下午 02:55:33
 */
package elaborate.vwbe.demo;

import elaborate.vwbe.VWBEApplication;
import elaborate.vwbe.impl.DefaultVWBEApplicationBuilder;
import elaborate.vwbe.scripting.ScriptLanguage;
import elaborate.vwbe.scripting.ScriptingException;
import java.io.IOException;
import java.io.StringWriter;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.DefaultTableModel;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Node;

/**
 *
 * @author lendle
 */
public class DemoApplication extends javax.swing.JFrame {

    private JFileChooser fileChooser = new JFileChooser(".");
    private VWBEApplication vWBEApplication = null;
    private List<String> scriptFunctions=new ArrayList<String>();
    private JComboBox comboParamTypes=new JComboBox();

    /** Creates new form DemoApplication */
    public DemoApplication() {
        initComponents();
        loadSupportedCharsets();
        loadSupportedTypes();
        FileFilter filter1 = new FileNameExtensionFilter("(X)HTML file", "html", "html", "xhtml");
        this.fileChooser.addChoosableFileFilter(filter1);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();
        tfSrc = new javax.swing.JTextField();
        buttonGO = new javax.swing.JButton();
        buttonBrowse = new javax.swing.JButton();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        jScrollPane1 = new javax.swing.JScrollPane();
        taStatus = new javax.swing.JTextArea();
        scrollPane = new javax.swing.JScrollPane();
        taResult = new javax.swing.JTextArea();
        jSplitPane1 = new javax.swing.JSplitPane();
        jPanel1 = new javax.swing.JPanel();
        comboFunctionHeaders = new javax.swing.JComboBox();
        jScrollPane2 = new javax.swing.JScrollPane();
        taFunctionContent = new javax.swing.JTextArea();
        jPanel2 = new javax.swing.JPanel();
        jScrollPane3 = new javax.swing.JScrollPane();
        tableParameters = new javax.swing.JTable();
        jPanel3 = new javax.swing.JPanel();
        buttonExecute = new javax.swing.JButton();
        comboCharacterEncoding = new javax.swing.JComboBox();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("VWBE DemoApp");

        jLabel1.setText("Source XHTML File:");

        tfSrc.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                tfSrcKeyReleased(evt);
            }
        });

        buttonGO.setText("GO");
        buttonGO.setEnabled(false);
        buttonGO.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonGOActionPerformed(evt);
            }
        });

        buttonBrowse.setText("...");
        buttonBrowse.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonBrowseActionPerformed(evt);
            }
        });

        taStatus.setColumns(20);
        taStatus.setRows(5);
        jScrollPane1.setViewportView(taStatus);

        jTabbedPane1.addTab("Status", jScrollPane1);

        taResult.setColumns(20);
        taResult.setRows(5);
        scrollPane.setViewportView(taResult);

        jTabbedPane1.addTab("Result", scrollPane);

        jSplitPane1.setDividerLocation(250);

        jPanel1.setLayout(new java.awt.BorderLayout());

        comboFunctionHeaders.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                comboFunctionHeadersActionPerformed(evt);
            }
        });
        jPanel1.add(comboFunctionHeaders, java.awt.BorderLayout.PAGE_START);

        taFunctionContent.setColumns(20);
        taFunctionContent.setEditable(false);
        taFunctionContent.setLineWrap(true);
        taFunctionContent.setRows(5);
        jScrollPane2.setViewportView(taFunctionContent);

        jPanel1.add(jScrollPane2, java.awt.BorderLayout.CENTER);

        jSplitPane1.setLeftComponent(jPanel1);

        jPanel2.setLayout(new java.awt.BorderLayout());

        tableParameters.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "Parameter", "Value", "Type"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.String.class, java.lang.String.class
            };
            boolean[] canEdit = new boolean [] {
                false, true, true
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        jScrollPane3.setViewportView(tableParameters);

        jPanel2.add(jScrollPane3, java.awt.BorderLayout.CENTER);

        jPanel3.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT));

        buttonExecute.setText("Execute");
        buttonExecute.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonExecuteActionPerformed(evt);
            }
        });
        jPanel3.add(buttonExecute);

        jPanel2.add(jPanel3, java.awt.BorderLayout.SOUTH);

        jSplitPane1.setRightComponent(jPanel2);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 738, Short.MAX_VALUE)
                    .addComponent(jTabbedPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 738, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(tfSrc, javax.swing.GroupLayout.PREFERRED_SIZE, 434, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(buttonBrowse)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(comboCharacterEncoding, 0, 90, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(buttonGO)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(tfSrc, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(buttonGO)
                    .addComponent(buttonBrowse)
                    .addComponent(comboCharacterEncoding, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 583, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jTabbedPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 162, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

private void buttonBrowseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonBrowseActionPerformed
// TODO add your handling code here:
    if (this.fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
        try {
            this.tfSrc.setText(this.fileChooser.getSelectedFile().toURI().toURL().toString());
            this.buttonGO.setEnabled(true);
        } catch (IOException ex) {
            Logger.getLogger(DemoApplication.class.getName()).log(Level.SEVERE, null, ex);
            this.taStatus.append(ex.getLocalizedMessage() + "\r\n");
        }
    }
}//GEN-LAST:event_buttonBrowseActionPerformed

private void buttonGOActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonGOActionPerformed
// TODO add your handling code here:
    DefaultVWBEApplicationBuilder builder = new DefaultVWBEApplicationBuilder();
    builder.setCharacterEncoding((String) this.comboCharacterEncoding.getSelectedItem());
    try {
        this.vWBEApplication = builder.createVWBEApplication(new URL(this.tfSrc.getText()));
        //load script function headers
        Iterator<String> it=this.vWBEApplication.getDeclaredScriptFunctions(ScriptLanguage.JavaScript);
        this.comboFunctionHeaders.removeAllItems();
        scriptFunctions.clear();
        while(it.hasNext()){
            String function=it.next();
            this.scriptFunctions.add(function);
            int index=function.indexOf("{");
            this.comboFunctionHeaders.addItem(function.substring(0, index));
        }
        selectScriptFunction(0);
        this.taStatus.append("url parsed successfully" + "\r\n");
    } catch (Exception ex) {
        Logger.getLogger(DemoApplication.class.getName()).log(Level.SEVERE, null, ex);
        this.taStatus.append(ex.getLocalizedMessage() + "\r\n");
    }
}//GEN-LAST:event_buttonGOActionPerformed


private void tfSrcKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_tfSrcKeyReleased
// TODO add your handling code here:
    if (this.tfSrc.getText().trim().length() > 0) {
        this.buttonGO.setEnabled(true);
    } else {
        this.buttonGO.setEnabled(false);
    }
}//GEN-LAST:event_tfSrcKeyReleased

private void comboFunctionHeadersActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_comboFunctionHeadersActionPerformed
// TODO add your handling code here:
    this.selectScriptFunction(this.comboFunctionHeaders.getSelectedIndex());
    String functionHeader=(String) this.comboFunctionHeaders.getSelectedItem();
    int index1=functionHeader.indexOf("(");
    int index2=functionHeader.lastIndexOf(")");
    DefaultTableModel model=(DefaultTableModel) this.tableParameters.getModel();
    while(model.getRowCount()>0){
        model.removeRow(0);
    }
    if(index2>index1){
        String params=functionHeader.substring(index1+1, index2);
        String [] paramArray=params.split(",");
        if(paramArray!=null && paramArray.length>0){
            for(String param : paramArray){
                if(param.trim().length()>0){
                    model.addRow(new Object[]{param.trim(), "", "String"});
                }
            }
        }
    }
}//GEN-LAST:event_comboFunctionHeadersActionPerformed

private void buttonExecuteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonExecuteActionPerformed
// TODO add your handling code here:
    String function=(String) this.comboFunctionHeaders.getSelectedItem();
    if(function!=null){
            try {
                int index1=function.indexOf("function")+"function".length();
                int index2=function.indexOf("(");
                String functionName=function.substring(index1+1, index2).trim();
                String executingExpression=functionName+"(";
                DefaultTableModel model=(DefaultTableModel) this.tableParameters.getModel();
                List argExpressions=new ArrayList();
                for(int i=0; i<model.getRowCount(); i++){
                    if(i>0){
                        executingExpression+=", ";
                    }
                    String parameter=(String) model.getValueAt(i, 1);
                    String type=(String) model.getValueAt(i, 2);
                    executingExpression+=model.getValueAt(i, 1);
                    if("String".equals(type)){
                        argExpressions.add(parameter);
                    }
                    else if("Double".equals(type)){
                        argExpressions.add(Double.valueOf(parameter));
                    }
                    else if("Integer".equals(type)){
                        argExpressions.add(Integer.valueOf(parameter));
                    }
                    else if("Long".equals(type)){
                        argExpressions.add(Long.valueOf(parameter));
                    }
                    else if("Float".equals(type)){
                        argExpressions.add(Float.valueOf(parameter));
                    }
                    else{
                        argExpressions.add(parameter);
                    }
                }
                executingExpression+=");";
                this.taStatus.append("Executing: "+executingExpression+"\r\n");
                Object result=this.vWBEApplication.invokeScriptFunction(ScriptLanguage.JavaScript, functionName, argExpressions.toArray());
                if(result instanceof Node){
                    try {
                        Node node=vWBEApplication.applyH2X((Node)result);
                        Transformer tf = TransformerFactory.newInstance().newTransformer();
                        StringWriter strWriter = new StringWriter();
                        tf.setOutputProperty(OutputKeys.INDENT, "yes");
                        tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
                        tf.transform(new DOMSource(node), new StreamResult(strWriter));
                        this.taResult.append(""+strWriter.getBuffer()+"\r\n");
                    } catch (Exception ex) {
                        Logger.getLogger(DemoApplication.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                else{
                    this.taResult.append(""+result+"\r\n");
                }
                this.jTabbedPane1.setSelectedIndex(1);
            } catch (ScriptingException ex) {
                Logger.getLogger(DemoApplication.class.getName()).log(Level.SEVERE, null, ex);
                this.taStatus.append(ex.getLocalizedMessage()+"\r\n");
            }
    }
}//GEN-LAST:event_buttonExecuteActionPerformed

private void selectScriptFunction(int index){
    this.taFunctionContent.setText(this.scriptFunctions.get(index));
}

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(DemoApplication.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(DemoApplication.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(DemoApplication.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(DemoApplication.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                DemoApplication app = new DemoApplication();
                app.setLocationRelativeTo(null);
                app.setVisible(true);
            }
        });
    }

    private void loadSupportedCharsets() {
        int defaultIndex = 0;
        Iterator<String> names = Charset.availableCharsets().keySet().iterator();
        int index = 0;
        while (names.hasNext()) {
            String name = names.next();
            this.comboCharacterEncoding.addItem(name);
            if (name.toLowerCase().equals("utf-8")) {
                defaultIndex = index;
            }
            index++;
        }
        this.comboCharacterEncoding.setSelectedIndex(defaultIndex);
    }
    
    private void loadSupportedTypes(){
        this.comboParamTypes.addItem("String");
        this.comboParamTypes.addItem("Double");
        this.comboParamTypes.addItem("Integer");
        this.comboParamTypes.addItem("Long");
        this.comboParamTypes.addItem("Float");
        this.tableParameters.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(this.comboParamTypes));
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton buttonBrowse;
    private javax.swing.JButton buttonExecute;
    private javax.swing.JButton buttonGO;
    private javax.swing.JComboBox comboCharacterEncoding;
    private javax.swing.JComboBox comboFunctionHeaders;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JScrollPane scrollPane;
    private javax.swing.JTextArea taFunctionContent;
    private javax.swing.JTextArea taResult;
    private javax.swing.JTextArea taStatus;
    private javax.swing.JTable tableParameters;
    private javax.swing.JTextField tfSrc;
    // End of variables declaration//GEN-END:variables
}
